﻿#pragma once

#include"Common.h"

//#ifdef _WIN32
//	#include<Windows.h>
//#else
//// linux下brk mmap等 
//#endif

//malloc是一个内存池，但是要考虑各种情况
//下面写的是一个针对单一情况的内存池，效率更高

//定长内存池
//template<size_t N>
//class ObjectPool
//{
//
//};

//// 直接去堆上按⻚申请空间 
//inline static void* SystemAlloc(size_t kpage)
//{
//#ifdef _WIN32					//假设一页是8K
//	void* ptr = VirtualAlloc(0, kpage * 8 * 1024, MEM_COMMIT | MEM_RESERVE,
//		PAGE_READWRITE);		//位运算kpage>>13
//#else
//	// linux下brk mmap等 
//#endif
//	if (ptr == nullptr)
//		throw std::bad_alloc();
//	return ptr;
//}



//每次都以类型T对象大小申请内存
//对象池
template<class T>
class ObjectPool
{
public:
	//申请内存	
	T* New()
	{
		T* obj = nullptr;
		//优先把还回来内存块对象，再次重复利用
		if (_freeList)
		{
			void* next = *(void**)_freeList;//取到了第二个内存块地址
			obj = (T*)_freeList;//第一块内存块
			_freeList = next;
		}
		else
		{
			//剩余内存不够一个对象大小时，则重新开大块空间
			if (_remainBytes < sizeof(T))//剩余内存不够申请一个对象
			{							//剩余内存就丢了
				_remainBytes = 128 * 1024;//8*1024*32 即一次开辟16页
				//_memory = (char*)malloc(_remainBytes);
				_memory = (char*)SystemAlloc(_remainBytes/(8*1024));//封装了系统调用,脱离malloc
				if (_memory == nullptr)		//位运算_remainBytes>>13
				{
					throw std::bad_alloc();
				}
			}
			obj = (T*)_memory;
			size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
			//比指针大，以T空间大小开辟
			//比指针小，以指针空间大小开辟	保证_freeList链表能正常存下地址
			_memory += objSize;
			_remainBytes -= objSize;
		}
		//定位new,显示调用T的构造函数初始化
		new(obj)T; 

		return obj;
		
	}
	//释放内存	归还	往_freeList链表挂
	void Delete(T* obj)
	{
		//显示调用析构函数清理对象
		obj->~T();	// 显式调用对象的析构函数，用于清理 obj 所指向的对象的内容。
					// 注意：这并不会释放 obj 本身所占用的内存（例如 obj 是在栈上或堆上分配的原始指针）。
					// 如果 T 是 std::vector，则会调用 vector 的析构函数，
					// 清理 vector 内部动态分配的资源（如堆上的元素存储空间）。
					// 这种方式通常用于使用 placement new 构造的对象，或者手动管理生命周期的场景。

		//if (_freeList == nullptr)
		//{
		//	_freeList = obj;		//指向第一个内存块
		//	//*(int*)obj = nullptr;	//第一个内存块前4字节置nullptr

		//	*(void**)obj = nullptr;//在32位/64位下都可以执行
		//							//解引用把obj看成了void*类型，4/8字节
		//}
		//else
		//{
		//	//头插
		//	*(void**)obj = _freeList;
		//	_freeList = obj;
		//}
		
		//上述if else执行相同代码，可用下面代替
		//头插
		* (void**)obj = _freeList;
		_freeList = obj;
	}

private:
	char* _memory = nullptr;	//指向大块内存的指针
								//char方便以字节为单位切内存
	void* _freeList = nullptr;	//归还的内存形成链表的头指针，
								//每个内存块头四个(8个)字节存下一个内存块地址
	size_t _remainBytes = 0;	//大块内存在切分过程中剩余字节数

	//无法释放内存，有的没有归还，有的归还了，随进程结束释放
	//不需要释放，一直在_freeList反复使用
};



//全局函数TestObjectPool不能被多个.cpp包含，重复定义
////性能测试
//struct TreeNode
//{
//	int _val;
//	TreeNode* _left;
//	TreeNode* _right;
//	TreeNode()
//		:_val(0)
//		, _left(nullptr)
//		, _right(nullptr)
//	{}
//};
//void TestObjectPool()
//{
//	// 申请释放的轮次 
//	const size_t Rounds = 3;
//	// 每轮申请释放多少次 
//	const size_t N = 100000;
//	size_t begin1 = clock();
//	std::vector<TreeNode*> v1;
//	v1.reserve(N);
//	for (size_t j = 0; j < Rounds; ++j)
//	{
//		for (int i = 0; i < N; ++i)
//		{
//			v1.push_back(new TreeNode);
//		}
//		for (int i = 0; i < N; ++i)
//		{
//			delete v1[i];
//		}
//		v1.clear();
//	}
//	size_t end1 = clock();
//	ObjectPool<TreeNode> TNPool;
//	size_t begin2 = clock();
//	std::vector<TreeNode*> v2;
//	v2.reserve(N);
//	for (size_t j = 0; j < Rounds; ++j)
//	{
//		for (int i = 0; i < N; ++i)
//		{
//			v2.push_back(TNPool.New());
//		}
//		for (int i = 0; i < 100000; ++i)
//		{
//			TNPool.Delete(v2[i]);
//		}
//		v2.clear();
//	}
//	size_t end2 = clock();
//	cout << "new cost time:" << end1 - begin1 << endl;
//	cout << "object pool cost time:" << end2 - begin2 << endl;
//}